package com.weme.common.manager

import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.google.protobuf.ByteString
import com.osom.proto.message.Brocast
import com.osom.proto.message.NetworkOuterClass
import com.weme.common.AppConfig.WEBSOCKET_IP
import com.weme.common.network.NetWorkUrl
import com.weme.common.socket.base.HandlerWebSocketClient
import com.weme.common.util.UserMKHelper
import dev.kratos.api.user_server.v1.Accounts
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import java.net.URI

/**
 * Socket 连接管理类
 *
 * @author
 */
object SocketConnectManager {

    val TAG = this::class.java.simpleName

    private val lifecycleOwner = ProcessLifecycleOwner.get()

    private val applicationScope = lifecycleOwner.lifecycleScope

    private var client: HandlerWebSocketClient? = null


    /**
     * 消息的处理类
     */
    private val handler = MessageHandler()

    /**
     * 收到的Network数据会从这个传递出去
     */
    val netWorkReceiver = handler.netWorkReceiver

    val netWorkReceiverForever = handler.getForeverReceiver()

    val openService = handler.getOpenService()

    val errorService = handler.getErrorService()

    val accountLiveData: MutableLiveData<Accounts> = MutableLiveData()


    val callVideoLiveData: MutableLiveData<Any> = MutableLiveData()


    val callLiveData: MutableLiveData<Any> = MutableLiveData()//来电
    val matchLiveData: MutableLiveData<Any> = MutableLiveData()//匹配结束继续匹配
//    val answerViewListdata: MutableLiveData<Brocast.VideoCallMessage> = MutableLiveData()//接听视频电话
  //  val msgList = handler.msgList


    /**
     * 返回自己在在意的数据类型
     *
     * @param cmdId 在意的cmdId
     *
     * @param care 变换
     *
     * @author
     */
    fun <T> careReceiver(cmdId: Int, care: (ByteString) -> T) = handler.careReceiver(cmdId, care)

    /**
     * 断线重连
     */
    private var reConnectJob: Job? = null

    /**
     * 是否连接成功
     */
    fun isConnect() = client?.isOpen == true

    /**
     * 是否登陆成功
     */
    private var isLogin = true

    /**
     * socket 登陆成功返回的用户唯一标识
     */
    private var uKey = 0L
    fun getUKey() = uKey

    /**
     * 发送消息
     */
    fun send(msg: Any,cmdId: Int,seq:Long) {
        if (client?.isOpen == true){
            client?.send(msg,cmdId,seq)
        }else{
            val foundItem = enumValues<NetWorkUrl>().find { it.seq == seq }
            Log.e("socket", "error 消息发送失败 seq=$seq method = ${foundItem?.name}")
            startReConnect()
            //    UtilsApp.getTopActivity().showToast("Connecting to server")
        }
    }


    init { //        applicationScope.launch { //在这里监听一下登陆的返回
        //            netWorkReceiver.filter {
        //                it.cmdid == CMDID_LOGIN_RSP || it.cmdid == NetworkOuterClass.NetworkCommand.CMD_GATEWAY_API_RESPONSE.number
        //            }.observe(lifecycleOwner) {
        //                Log.e(MessageHandler.TAG, "接收到消息 seq = " + it.messageseq+" code = "+it.code+ "msg"+it.msg)
        //                when (it.cmdid) {
        //                    NetworkOuterClass.NetworkCommand.CMD_GATEWAY_API_RESPONSE.number -> {
        //                        if (it.code != 0 && it.messageseq != NetWorkUrl.CheckLogin.seq) {
        //                            UtilsApp.getTopActivity().showToast(it.msg + "" + it.code)
        //                        }
        //                    }
        //                }
        //                HeatBeat.sendHeatBeat()
        //            }
        //        }
    }


    /**
     * 连接服务器
     */
    private suspend fun connectSocket() = flow {
        emit(SocketConnectManager::connectOperate)
    }.filter {
        !isConnect()
    }.map {
        client = it()
        client
    }


    private suspend fun userLogin() = flow {
        emit(SocketConnectManager::loginOperate)
    }.filter {
        !isLogin
    }.map {
        client = it()
        client
    }

    /**
     * 开启断线重连
     *
     * @param delay 是否延时重连
     */
    fun startReConnect(delay: Boolean = false) {
        if (reConnectJob?.isActive == true) {
            return
        }

        Log.e("socket", "startReConnect")

        reConnectJob = applicationScope.launch(Dispatchers.IO) {
            flow {
                if (delay) {
                    delay(1 * 1000L)
                }
                emit(innerDisconnect())
                emitAll(connectSocket())
                emitAll(userLogin())
            }
                .retryWhen { throwable, _ ->
                    // 如果你想在重连尝试之间引入延迟，请取消注释以下行
                    // val time = waitting(waiting++)
                     Log.e(TAG, "遇到错误。${0}秒后重新连接。错误详细信息：${Log.getStackTraceString(throwable)}")
                    // delay(time * 1000)
                    true // 你可以根据某些条件控制何时重试
                }
                .catch { exception ->
                    // 如果需要，可以在这里处理异常
                    Log.e("socket", "重连失败：${exception.message}")
                }
                .collect { }
        }
    }


    /**
     * 停止断线重连
     */
    private fun stopReConnect() {
        if (reConnectJob?.isActive == true) reConnectJob?.cancel()
    }

    fun disConnect() = applicationScope.launch(Dispatchers.IO) {
        innerDisconnect()
        stopReConnect()
    }

    private fun innerDisconnect(): HandlerWebSocketClient? {
        Log.e("socket", "innerDisconnect")
        HeatBeat.stopHeatBeat()
        if (isConnect()) {
            client?.closeBlocking()
        }
        isLogin = false
        return client
    }

    /**
     * 这是一个耗时操作
     */
    private fun connectOperate(): HandlerWebSocketClient {

        val uri = URI.create(WEBSOCKET_IP)
        return HandlerWebSocketClient(uri).also {
            it.setHandler(handler)
            it.setCodecFactory(MessageCoderFactory())
            it.connectBlocking()
        }
    }

    private fun loginOperate(): HandlerWebSocketClient? { //        val loginBuilder = Login.LoginRequest.newBuilder()
        //        loginBuilder.session = SpStorage.common[SpStorage.KEYS.SESSION, ""]
        //        val login = loginBuilder.build()
        //        client?.send(login)
        return client
    }

    /**
     * 出错后连接不上，再继续重连改为10秒
     */
    private fun waitting(waiting: Int): Long {
        return 2
    }
}